//implementation and test of AudioPlayer class
#include "AudioPlayer.h"

#include <iostream>
#include <fstream>
#include <vector>
#include <cassert>
using namespace std;


///////// Definitions for AudioPlayer ////////////

 

int AudioPlayer::checkError(void) {
  if(_err) { 
    Pa_Terminate(); 
    fprintf( stderr, "An error occured while using the portaudio stream\n" );
    fprintf( stderr, "Error number: %d\n", _err );
    fprintf( stderr, "Error message: %s\n", Pa_GetErrorText( _err ) );
    throw "Returning from error.";
  }
  return 0;
}


// right now we're only worrying about one stream. Later, maybe I'll
// add something that will do 2 streams
void AudioPlayer::setAudio(std::vector<float> signal, int sampleRate) {
  printf("Set Audio Data\n");
  _signal     = signal;
  _sampleRate = sampleRate;
  _hasSignal  = true;
  return;
}

int AudioPlayer::startAudio(void) {
  if(!_hasSignal) { return 1; }
  
  _lastIndex = -1; //start playing from the beginning.
  
  // can do this instead of having multiple goto's accross functions
  try {
    
    _err = Pa_Initialize();
    checkError();
    _err = Pa_OpenDefaultStream(
				&_stream,
				0,              /* no input channels */
				2,              /* stereo output */
				paFloat32,      /* 32 bit floating point output */
				_sampleRate,
				256,            /* frames per buffer */	   
				this->paOutputCallback,
				this );  
    checkError();
    printf("Opened Audio Stream\n");

    _err = Pa_StartStream( _stream );
    checkError();

  } catch (char* e) {
    printf("There was an error: %s\n", e);
  }

  return _err;
}

int AudioPlayer::stopAudio(void) {
  
  try {
    _err = Pa_StopStream( _stream );
    //if( err != paNoError ) goto error;
    _err = Pa_CloseStream( _stream );
    //if( err != paNoError ) goto error;
    Pa_Terminate();
    printf("\nClosed Audio Stream\n");

  } catch (char* e) {
    printf("There was an error: %s\n", e);
  }

  return _err;

}

int AudioPlayer::paOutputCallback( const void *inputBuffer, void *outputBuffer,
				   unsigned long framesPerBuffer,
				   const PaStreamCallbackTimeInfo* timeInfo,
				   PaStreamCallbackFlags statusFlags,
				   void *userData ) {  

  AudioPlayer* data = static_cast<AudioPlayer*>(userData);
  float* out = (float*)outputBuffer;

  (void) inputBuffer;

  for( unsigned i=0; i<framesPerBuffer; i++ ) {
    data->_lastIndex = ( (data->_lastIndex + 1) % data-> _signal.size() );
    *out++ = data->_signal[data->_lastIndex];// out+=1;
    *out++ = data->_signal[data->_lastIndex]; //out+=1;
  }
  
  return 0;
}

////////////////// End AudioPlayer Definitions //////////



///////////////////// Test Code /////////////////////////


// Recall that get() function did not work! I had to use read()!
vector< float > load_mat(const char* fpath) {
  ifstream fin(fpath);
  if( !fin) { printf("error"); }
  assert(fin);
 
  int len;
  fin.read( (char*)&len, 4);
 
  float R[len]; 
  fin.read((char*)&R, len*sizeof(float)); 
  fin.close();
 
  vector< float > v(len);
 
  for(int i = 0; i < len; i+=1) { 
    v[i] = R[i];
  }
  return v;
}



/* Test our AudioPlayer */
int main(void) {

  vector<float> signal;
  signal = load_mat("../fltkTest/out.sig");
  
  AudioPlayer p;
  
  p.setAudio(signal, 44100);
  // This should probably take an optional 'timer'?
  p.startAudio();
  sleep(3);
  p.stopAudio();

  
  return 0;
}


////////////// End Test Code //////////// 
//                (fin)
